﻿#include "GUIScaleDialog.h"
#include "ui_GUIScaleDialog.h"

#include "PickDataProvider/GUIPickInfo.h"
#include "PickDataProvider/PickedData.h"
#include "PickDataProvider/PickedDataProvider.h"
#include "OperatorsInterface/GraphEventOperator.h"
#include "OperatorsInterface/TreeEventOperator.h"

#include "FITK_Kernel/FITKCore/FITKOperatorRepo.h"
#include "FITK_Kernel/FITKCore/FITKDataRepo.h"
#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsDiscModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsSEAModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractSEASubSys.h"
#include "FITK_Component/FITKAcousticsModel/FITKSEAAbstractJunction.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsFEModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractFESubSys.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsFEFace.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsSensors.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsGeometryData.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKAcousticsPhysics.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKAcousticsLoadManager.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKAbsVirtualTopo.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKAbsVirtualTopoMapper.h"

#include "FITK_Kernel/FITKCore/FITKActionOperator.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKAbsGeomTools.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKGeoInterfaceFactory.h"
#include "PickDataProvider/PickedData.h"
#include "PickDataProvider/PickedDataProvider.h"

#include "FITK_Component/FITKAcousticsModel/FITKAcousticsSEAModel.h"
#include "FITK_Kernel/FITKCore/FITKVec3D.h"
#include "FITK_Kernel/FITKCore/FITKVec3DAlg.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsDiscNodeList.h"

#include "FITK_Component/FITKAcousticsModel/FITKAbstractSEAFace.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsTriangles.h"
#include "FITK_Component/FITKAcousticsModel/FITKSEASubSysBeam.h"
#include "FITK_Component/FITKAcousticsModel/FITKSEAFlatCurvedFace.h"
#include "FITK_Component/FITKAcousticsModel/FITKSEASubSysShellPlate.h"
#include "FITK_Interface/FITKInterfaceModel/FITKAbstractElement.h"
#include "FITK_Component/FITKAcousticsModel/FITKSEASubSysShellCurved.h"
#include "FITK_Interface/FITKInterfaceModel/FITKElementFactory.h"

#include <QSet>
#include <QMessageBox>

#define _SEA_SUBSYSTEM_ 0
#define _FE_SUBSYSTEM_ 1
#define _SEA_SHELL_ 2
#define _SEA_BEAM_ 3

namespace GUI
{
    GUIScaleDialog::GUIScaleDialog(Core::FITKActionOperator* oper, QWidget* parent /*= nullptr*/) :
        GUIDialogBase(FITKAPP->getGlobalData()->getMainWindow()) ,_oper(oper)
    {
        _ui = new Ui::GUIScaleDialog();
        _ui->setupUi(this);
        // 设置对话框关闭时自动删除
        setAttribute(Qt::WA_DeleteOnClose);
        //去掉问号
        Qt::WindowFlags flags = windowFlags();
        flags &= ~Qt::WindowContextHelpButtonHint;
        setWindowFlags(flags);
        this->init();
    }

    GUIScaleDialog::~GUIScaleDialog()
    {
        if (_ui) {
            delete _ui;
            _ui = nullptr;
        }
        //所有的类在执行完毕后，将清空对3维的操作
        GraphData::PickedDataProvider* provider = GraphData::PickedDataProvider::getInstance();
        if (provider == nullptr)return;
        provider->clearPickedData();//清空拾取数据
        //拾取对象 关闭
        //拾取方式 空
        GUI::GUIPickInfoStru pickInfo = GUI::GUIPickInfo::GetPickInfo();
        pickInfo._pickObjType = GUI::GUIPickInfo::PickObjType(GUI::GUIPickInfo::POBJNone);
        pickInfo._pickMethod = GUI::GUIPickInfo::PickMethod(GUI::GUIPickInfo::PickMethod::PMNone);
        //设置拾取方式
        GUI::GUIPickInfo::SetPickInfo(pickInfo);
    }

    void GUIScaleDialog::init()
    {
        setWindowTitle(tr("Scale"));
        _ui->comboBox_Model->addItem("Plate", _SEA_SHELL_);
        _ui->comboBox_Model->addItem("Beam", _SEA_BEAM_);
        _ui->comboBox_Object->addItem("SEAsubsystem", _SEA_SUBSYSTEM_);
        _ui->comboBox_Object->addItem("FEsubsystem", _FE_SUBSYSTEM_);
        _ui->Point_lineEditX_2->setText("1");
        _ui->Point_lineEditY_2->setText("1");
        _ui->Point_lineEditZ_2->setText("1");
    }

    void GUIScaleDialog::pickFinishedOper()
    {
        //获取拾取数据
        GraphData::PickedDataProvider* provider = GraphData::PickedDataProvider::getInstance();
        if (provider == nullptr)return;
        disconnect(provider, SIGNAL(sig_pickedOver()), this, SLOT(slotPickOverEvent()));
        QList<GraphData::PickedData*> pickList = provider->getPickedList();
        QList<Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode> nodes;
        for (GraphData::PickedData* pickData : pickList)
        {
            if (!pickData) continue;
            GraphData::PickedDataType pickType = pickData->getPickedDataType();
            if (GraphData::PickedDataType::DiscNodePick == pickType)
                nodes.append(pickData->getPickedDiscNodes());
        }
        //根据id获取点的xyz
        if (_DiscModel == nullptr) return;
        Acoustics::FITKAcousticsDiscNodeList* nodelist = _DiscModel->getNodes();
        if (nodelist == nullptr) return;
        if (_flag == 1)
        {
            _pointID = nodes[0]._id;
            Core::FITKNode* node = nodelist->getNodeByID(_pointID);
            if (node == nullptr) return;
            _ui->Point_lineEditX->setText(QString::number(node->x()));
            _ui->Point_lineEditY->setText(QString::number(node->y()));
            _ui->Point_lineEditZ->setText(QString::number(node->z()));
        }

        else if (_flag == 2)
        {
            QList<GraphData::PickedData*> pickList = provider->getPickedList();
            GraphData::PickedData* pickData = pickList.at(0);
            if (pickData == nullptr) return;
            _modelObjID = pickData->getPickedDataObjId();
            _ui->label_Model->setText(_modelObjID == -1 ? tr("Picked (0)") : tr("Picked (1)"));
        }
    }

    void GUIScaleDialog::scaleSEAObj()
    {
        double xV = _ui->Point_lineEditX->text().toDouble();
        double yV = _ui->Point_lineEditY->text().toDouble();
        double zV = _ui->Point_lineEditZ->text().toDouble();
        if (_DiscModel == nullptr || _SEAModel == nullptr) return;
        // 获取离散模型的节点列表
        Acoustics::FITKAcousticsDiscNodeList* disNodeList = _DiscModel->getNodes();
        if (disNodeList == nullptr) return;
        // 获取SEA模型的子系统管理器
        Acoustics::FITKAcousticsSEASubSysManager* subsystemManager = _SEAModel->getSEASubSysManager();
        Acoustics::FITKSEAFaceManager* faceManager = _SEAModel->getSEAFaceManager();
        if (subsystemManager == nullptr || faceManager == nullptr) return;

        // 根据ID获取子系统对象
        Acoustics::FITKAbstractSEASubSysWithNodes* obj = dynamic_cast<Acoustics::FITKAbstractSEASubSysWithNodes*>(subsystemManager->getDataByID(_modelObjID));
        if (obj == nullptr) return;
        Acoustics::FITKAbstractSEAFace* face = obj->getFaceObj();
        if (face == nullptr) return;
        Acoustics::FITKAcousticsTriangles* triang = face->getTriangleMesh();
        if (triang == nullptr) return;
        //获取节点列表
        QList<int> noodeList = obj->getNodeIDs();
        QList<int> triNodeList = obj->getTriangleNodeIDs();
        QSet<int> allNodeList = noodeList.toSet().unite(triNodeList.toSet());

        Acoustics::FITKAbstractSEASubSysWithNodes* newObj = nullptr;
        //判断数据对象类型
        if (obj->getSEASubSysType() == Acoustics::FITKAbstractSEASubSys::SEASubSysType::SEABeam)
            newObj = new Acoustics::FITKSEASubSysBeam;
        else if (obj->getSEASubSysType() == Acoustics::FITKAbstractSEASubSys::SEASubSysType::SEAFlatPlate)
            newObj = new Acoustics::FITKSEASubSysPlateShell;
        else if (obj->getSEASubSysType() == Acoustics::FITKAbstractSEASubSys::SEASubSysType::SEASinglyCurvedShell)
            newObj = new Acoustics::FITKSEASubSysSinglyCurvedShell;
        else if (obj->getSEASubSysType() == Acoustics::FITKAbstractSEASubSys::SEASubSysType::SEADoublyCurvedShell)
            newObj = new Acoustics::FITKSEASubSysDoublyCurvedShell;
        //拷贝数据对象
        if (newObj == nullptr ) return;
        newObj->copy(obj);
        Acoustics::FITKAbstractSEAFace* newFace = newObj->getFaceObj();
        Acoustics::FITKAcousticsTriangles* newTriang = newFace->getTriangleMesh();
        subsystemManager->appendDataObj(newObj);
        //创建新节点做映射
        QHash<int, int> nodeIDs;
        for (int nodeID : allNodeList)
        {
            Core::FITKNode* node = disNodeList->getNodeByID(nodeID);
            if (node == nullptr) return;
            int newID = disNodeList->addNode((node->x() - xV) * _ui->Point_lineEditX_2->text().toDouble() + xV, (node->y() - yV) * _ui->Point_lineEditY_2->text().toDouble() + yV, (node->z() - zV) * _ui->Point_lineEditZ_2->text().toDouble() + zV);
            nodeIDs.insert(node->getNodeID(), newID);
        }
        //通过映射存入新节点
        QList<Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode> subSysNodeList = face->getNodes();
        QList<Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode> newSubSysNodeList;
        for (Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode subSysNode : subSysNodeList)
        {
            Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode newSubSysNode;
            newSubSysNode._id = nodeIDs[subSysNode._id];
            newSubSysNode._type = subSysNode._type;
            newSubSysNodeList.append(newSubSysNode);
        }
        //通过映射存入新三角形网格
        for (int i = 0; i < triang->getElementCount(); ++i)
        {
            Interface::FITKAbstractElement* element = triang->getElementAt(i);
            if (element == nullptr) return;
            Interface::FITKModelEnum::FITKEleType type = element->getEleType();
            Interface::FITKAbstractElement* newElement = Interface::FITKElementFactory::createElement(type);

            for (int j = 0; j < element->getNodeCount(); ++j)
                newElement->setNodeID(j, nodeIDs[element->getNodeID(j)]);
            newTriang->appendElement(newElement);
        }

        newFace->setNodes(newSubSysNodeList);
        if (!newObj->updateGeoProp()) return;
        _modelObjID = newObj->getDataObjectID();
    }

    void GUIScaleDialog::on_comboBox_Object_currentIndexChanged(int index)
    {
        _ui->comboBox_Model->clear();
        if (_ui->comboBox_Object->currentData().toInt() == _SEA_SUBSYSTEM_)
        {
            // SEA子系统
            _ui->comboBox_Model->addItem("Plate", _SEA_SHELL_);
            _ui->comboBox_Model->addItem("Beam", _SEA_BEAM_);
        }
        else if (_ui->comboBox_Object->currentData().toInt() == _FE_SUBSYSTEM_)
        {
            // FE子系统，暂时不做处理
        }
    }

    void GUIScaleDialog::on_pushButtonPoint1_Pick_clicked()
    { 
        _flag = 1;
        enablePickSig(GUI::GUIPickInfo::POBJDiscNode, GUI::GUIPickInfo::PickMethod::PMSingle);
        
    }

    void GUIScaleDialog::on_pushButtonModel_Pick_clicked()
    {
        //拾取模型
        _flag = 2;
        if (_ui->comboBox_Object->currentData().toInt() == _SEA_SUBSYSTEM_)
        {
            if (_ui->comboBox_Model->currentData().toInt() == _SEA_SHELL_)
                // SEA板
                enablePickSig(GUI::GUIPickInfo::POBJSEAShell, GUI::GUIPickInfo::PickMethod::PMSingle);
            else if (_ui->comboBox_Model->currentData().toInt() == _SEA_BEAM_)
                // SEA梁
                enablePickSig(GUI::GUIPickInfo::POBJSEABeam, GUI::GUIPickInfo::PickMethod::PMSingle);
        }
        else if (_ui->comboBox_Object->currentData().toInt() == _FE_SUBSYSTEM_)
        {
            // FE子系统
        }
    }

    void GUIScaleDialog::on_pushButton_OK_clicked()
    {
        if (_modelObjID == -1) 
        {
            QMessageBox::warning(this, tr("warn"), tr("Please select a model"));
            return;
        }

        if (_oper == nullptr) return;

        if (_ui->Point_lineEditX->text().isEmpty() || _ui->Point_lineEditY->text().isEmpty() || _ui->Point_lineEditZ->text().isEmpty())
        {
            QMessageBox::warning(this, tr("warn"), tr("Please select a reference point"));
            return;
        }
        if (_ui->Point_lineEditX_2->text().isEmpty() || _ui->Point_lineEditY_2->text().isEmpty() || _ui->Point_lineEditZ_2->text().isEmpty())
        {
            QMessageBox::warning(this, tr("warn"), tr("Please enter a zoom multiplier"));
            return;
        }
        if (_ui->Point_lineEditX_2->text().toDouble() < 0.001 || _ui->Point_lineEditY_2->text().toDouble() < 0.001 || _ui->Point_lineEditZ_2->text().toDouble() < 0.001)
        {
            QMessageBox::warning(this, tr("warn"), tr("The multiplier is too small"));
            return;
        }
        if (_ui->comboBox_Object->currentData().toInt() == _SEA_SUBSYSTEM_)
        this->scaleSEAObj();
        
        _oper->setArgs("objID", _modelObjID);

        this->accept();
    }

    void GUIScaleDialog::on_pushButton_Cancel_clicked()
    {
        this->close();
    }

    void GUIScaleDialog::enablePickSig(int pickObjType, int pickMethodType)
    {
        //获取拾取器，绑定拾取结束信号
        GraphData::PickedDataProvider* pickProvider = GraphData::PickedDataProvider::getInstance();
        //清除拾取对象所有的连接
        if (pickProvider != nullptr)
        {
            QObject::disconnect(pickProvider, SIGNAL(sig_pickedOver()), nullptr, nullptr);
            connect(pickProvider, &GraphData::PickedDataProvider::sig_pickedOver, this, &GUIScaleDialog::pickFinishedOper);
        }
        GUI::GUIPickInfoStru pickInfo = GUI::GUIPickInfo::GetPickInfo();
        pickInfo._pickObjType = GUI::GUIPickInfo::PickObjType(pickObjType);
        pickInfo._pickMethod = GUI::GUIPickInfo::PickMethod(pickMethodType);
        //设置拾取方式
        GUI::GUIPickInfo::SetPickInfo(pickInfo);
    }

}

